package com.zj.juc.study.completion;

import java.sql.Time;
import java.util.concurrent.*;

/**
 * @author 自己的名字
 * @version 1.0.0
 * @ClassName CompletableFutureMethodsDemo
 * @Description CompletableFuture 常用方法
 * @createTime 2024年12月21日 16:32
 */
public class CompletableFutureMethodsDemo {

    public static void main(String[] args) throws Exception{
        //CompletableFuture 方法
        //获取结果和触发计算


//        CompletableFuture<String> cf = getCf();
        //System.out.println(cf.get());//获取结果
        //        cfGetNow(cf);
//        TimeUnit.SECONDS.sleep(1);
//        cfComplete(cf);
        //apply出错了不会再往下调用
//        cfApply(true);
        //handler出错了还会往下调用
//        cfHandler(true);

//        cfThenAccept();
//        cfThenRun();
//        cfApplyThenEither();
//        cfThenCombine();
        homeWork();
    }

    /**
     * 立即返回结果，执行完毕则返回执行结果，否则返回默认值
     */
    private static void cfGetNow(CompletableFuture<String> cf){
        System.out.println(cf.getNow("hello world"));
    }

    /**
     * 立即打断并以value替代返回值,如果执行完毕则返回执行结果同时打断结果返回fale
     */
    private static void cfComplete(CompletableFuture<String> cf){
        boolean complete = cf.complete("complete");
        System.out.println(complete + cf.join());
    }


    private static CompletableFuture<String> getCf(){

        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return  "result";
        });
    }

    private static CompletableFuture<String> getCfWithExecutors(ExecutorService executorService,Boolean needException){
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(5);
                if (needException){
                    int result = 1/0;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return  "result";
        },executorService);
    }



    /**
     * 上一步的结果集可以作为下一步的参数同时可以一直调用
     * 如果出错了就不会再往下调用了
     */
    private static void cfApply(Boolean needException){
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> completableFuture = getCfWithExecutors(executorService,needException);
        CompletableFuture<String> nextFuture = completableFuture.thenApply(result -> {
            //result 执行结果
            return result + " next result";
        });
        executorService.shutdown();
        System.out.println(nextFuture.join());
    }

    /**
     * 跟apply是一样的功能，区别是出错了也会继续往下调用
     */
    private static void cfHandler(Boolean needException){
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> cf = getCfWithExecutors(executorService,needException);
        CompletableFuture<String> handle = cf.handle((result, ex) -> {
            if (ex == null) {
                System.out.println(result + " handler result");
            }
            return result + " handler result*2";
        });
        executorService.shutdown();
        System.out.println(handle.join());
    }

    /**
     * 下一个任务需要上个任务的执行结果但是这个任务没有返回值
     */
    private static void cfThenAccept(){
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> executors = getCfWithExecutors(executorService, false);
        executors.thenAccept(System.out::println);
        executorService.shutdown();
    }


    private static void cfThenRun(){
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> executors = getCfWithExecutors(executorService, false);
        CompletableFuture<Void> future = executors.thenRun(() -> {
            System.out.println("执行完毕");
        });
        System.out.println(executors.join());
        executorService.shutdown();
    }

    /**
     * 谁快返回谁
     */
    private static void cfApplyThenEither(){
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return  "player A";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return  "player B";
        });
        System.out.println(future1.applyToEither(future2, winner -> winner + "is winner").join());
    }


    private static void cfThenCombine(){
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return  "future1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return  "future2";
        });
        CompletableFuture<String> completableFuture = future1.thenCombine(future2, (one, two) -> {
            System.out.println("两个结果合并");
            return one + "=====" + two;
        });
        System.out.println(completableFuture.join());
    }


    private static void homeWork(){
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "----- come in 1");
            return 10;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "------ come in 2");
            return 20;
        }), (oneResult, twoResult) -> {
            System.out.println(Thread.currentThread().getName() + "------ come in 3");
            return 30;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "------ come in 4");
            return 40;
        }), (oneResult, twoResult) -> {
            return oneResult + twoResult;
        });
        System.out.println("main end ");
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
